package server;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.Vector;

import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;

import utils.ClientServerEnum;
import utils.ClientServerMessage;
import utils.Hashes;
import utils.PrintMsg;

import common.ClientEntity;
import common.Entity;
import common.Lists;
import common.Message;

import broadcast.Broadcast;
import broadcast.BroadcastListener;

public class ServerThread implements Runnable, ServerSendMsg
{
	private SSLSocket sslsocket;
	private String TimeStamp;
	private int ID;

	private Set<Entity> groupMembers;
	private Set<Entity> allMembers;
	private ClientServerMessage scm;
	private Map<Integer, ServerThread> ServerThreads;
	private ClientEntity ce;
	private int ClientID = -1; 
	private int ServerID = -1;	
	private static final String MessageDelimator = "\t\t";

	
	public ServerThread(int ServerID, SSLSocket s, int i)
	{
		this.ServerID = ServerID;
	
		this.sslsocket = s;
		this.ID = i;
	}

	public void run()
	{
		while (true)
		{
			try
			{
				BufferedInputStream is = new BufferedInputStream(sslsocket
						.getInputStream());
				InputStreamReader isr = new InputStreamReader(is);
				BufferedReader br = new BufferedReader(isr);
				String s = null;
				while ((s = br.readLine()) != null)
				{
					ProcessMsg(s);			
				}
			} 
			catch (Exception e)
			{
				System.out.println(e);
				SignOut();
				break;
			}
		}
		SignOut();
	}
	private void SendToClient(String s)
	{
		try
		{
			String write = s;
			BufferedOutputStream os = new BufferedOutputStream(sslsocket
					.getOutputStream());
			OutputStreamWriter osw = new OutputStreamWriter(os, "US-ASCII");
			osw.write(write);
			osw.flush();
		}
		catch (Exception e)
		{
			System.out.println(e);			
		}
	}
	
	private void ProcessMsg(String s)
	{
		scm = new ClientServerMessage(s);
		
		switch(scm.getMessageType())
		{
			case LOGIN:
				SignedIn();
				break;
			case LOGOUT:
				SignOut();
				break;
			case SEND_MESSAGE:
				SendMsgToclient();
				break;
			case RECIEVED_MESSAGE:
				RecievedMessage();
				break;
			case LIST_OF_SERVERS:
				SendLiveServer();
				break;
			default:
				break;	
		}
		
	}
	private boolean SendLiveServer()
	{
		StringBuilder sb = new StringBuilder();
		Vector<Queue<Entity>> shit = Lists.getInstance().getLiveServerList();
		for(Iterator<Queue<Entity>> it = Lists.getInstance().getLiveServerList().iterator(); it.hasNext();)
		{
			for(Iterator<Entity> inner = it.next().iterator(); inner.hasNext();)
			{
				Entity en = (Entity)inner.next();
				sb.append(en.getId()+" "+ en.getIp() + "\t");
			}
			sb.append("\n");
		}
		sb.append("END\n");
		this.SendToClient(sb.toString());
		
		PrintMsg.PrintStatic("Get Live Server List", null);
		
		return false;
	}
	
	private boolean SendMsgToclient()
	{
		RelayMessages.getInstance().
			SendMessage(this.ClientID, scm.getSendClientID(),
					    scm.getSendClientContent());
		return false;
	}
	
	
	private boolean RecievedMessage()
	{
		return false;
	}
	
	private boolean SignOut()
	{
		PrintMsg.PrintStatic("Signed Off", "Client ID: " + this.ClientID);
		if(this.ClientID == -1)return false;
		Lists.getInstance().deleteLiveClient(ce);
		return false;
	}
	
	private boolean SignedIn()
	{
		/*TODO put check password here..*/
		PrintMsg.PrintStatic("Signing In", null);
		this.ClientID = scm.getClientId();
	    this.ce = new ClientEntity(this.ClientID,scm.getPassword());
		
		List<ClientEntity> StaticClients = Lists.getInstance().getStaticClientList();
		
		if(StaticClients.contains(ce))
		{
			
			Lists.getInstance().addLiveClient(ce);
			RelayMessages.getInstance().AddThread(ClientID, this);
			
			PrintMsg.PrintStatic("Signed In", "Client ID: " + this.ClientID);
			SendToClient(ClientServerMessage.getContentOutput(ClientServerEnum.SIGNED_ON.ordinal(), "SIGNEDON"));
		}
		else
		{
			SendToClient(ClientServerMessage.getContentOutput(ClientServerEnum.INCORRECT_PASS.ordinal(), "INCORRECTPASS"));
			PrintMsg.PrintStatic("Incorrect Password", "Client ID: " + this.ClientID);
		}
		return false;
	}
	private Set<Entity> GetAllServers()
	{
		Entity[] LiveServerList = (Entity[]) Lists.getInstance().getStaticServerList().toArray();
		Set<Entity> AllServers = new HashSet<Entity>();
		
		for(int i = 0; i <LiveServerList.length; ++i)
		{
			synchronized (AllServers)
			{
				AllServers.add(LiveServerList[i]);
			}
		}
		
		return AllServers;
	}
	

	@Override
	public void deliverMsg(String msg)
	{
		SendToClient(msg);	
	}
}


